package com.yuyang.gulimall.ware.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yuyang.common.constant.OrderConstants;
import com.yuyang.common.exception.NoStockException;
import com.yuyang.common.to.SkuHasStockTo;
import com.yuyang.common.to.mq.OrderTo;
import com.yuyang.common.to.mq.SkuLockedDetail;
import com.yuyang.common.to.mq.SkuLockedTo;
import com.yuyang.common.utils.R;
import com.yuyang.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.yuyang.gulimall.ware.entity.WareOrderTaskEntity;
import com.yuyang.gulimall.ware.feign.OrderFeignService;
import com.yuyang.gulimall.ware.feign.ProductFeignService;
import com.yuyang.gulimall.ware.service.WareOrderTaskDetailService;
import com.yuyang.gulimall.ware.service.WareOrderTaskService;
import com.yuyang.gulimall.ware.vo.OrderItemVo;
import com.yuyang.gulimall.ware.vo.OrderVo;
import com.yuyang.gulimall.ware.vo.WareSkuLockVo;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuyang.common.utils.PageUtils;
import com.yuyang.common.utils.Query;

import com.yuyang.gulimall.ware.dao.WareSkuDao;
import com.yuyang.gulimall.ware.entity.WareSkuEntity;
import com.yuyang.gulimall.ware.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {
    @Autowired
    ProductFeignService productFeignService;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    WareOrderTaskDetailService wareOrderTaskDetailService;
    @Autowired
    WareOrderTaskService wareOrderTaskService;
    @Autowired
    OrderFeignService orderFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        LambdaQueryWrapper<WareSkuEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        String skuId = (String) params.get("skuId");
        String wareId = (String) params.get("wareId");
        lambdaQueryWrapper.eq(StringUtils.isNotBlank(skuId), WareSkuEntity::getSkuId,skuId)
                .eq(StringUtils.isNotBlank(wareId), WareSkuEntity::getWareId,wareId);
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                lambdaQueryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public void addOrUpdateStock(Long skuId, Long wareId, Integer skuNum) {
        LambdaQueryWrapper<WareSkuEntity> wareSkuEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
        wareSkuEntityLambdaQueryWrapper.eq(WareSkuEntity::getSkuId,skuId)
                .eq(WareSkuEntity::getWareId,wareId);
        WareSkuEntity wareSkuEntity = this.getOne(wareSkuEntityLambdaQueryWrapper);
        if (wareSkuEntity == null ){
            wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setSkuId(skuId);
            wareSkuEntity.setWareId(wareId);
            wareSkuEntity.setStock(skuNum);
            wareSkuEntity.setStockLocked(0);
            //TODO 远程调用查询sku的名称
            try {
                R info = productFeignService.info(skuId);
                Map<String,Object> skuInfo = (Map<String, Object>) info.get("skuInfo");
                if (info.getCode() ==0){
                    wareSkuEntity.setSkuName((String) skuInfo.get("skuName"));
                }
            } catch (Exception e) {
            }
            this.save(wareSkuEntity);
        }else {
            WareSkuEntity entity = new WareSkuEntity();
            entity.setId(wareSkuEntity.getId());
            this.update(entity,new LambdaUpdateWrapper<WareSkuEntity>().setSql("stock = stock +"+skuNum));
        }
    }

    @Override
    public List<SkuHasStockTo> hasStockBySkuIds(List<Long> skuIds) {
        List<SkuHasStockTo> collect = skuIds.stream().map(skuId -> {
            SkuHasStockTo skuHasStockTo = new SkuHasStockTo();
            skuHasStockTo.setSkuId(skuId);
            Long count = this.baseMapper.hasStockBySkuId(skuId);
            skuHasStockTo.setHasStock(count != null);
            return skuHasStockTo;
        }).collect(Collectors.toList());
        return collect;
    }
    //锁库存
    @Transactional
    @Override
    public Boolean skuWareLock(WareSkuLockVo wareSkuLockVo) {
        //保存订单的工作单
        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        wareOrderTaskEntity.setOrderSn(wareSkuLockVo.getOrderSn());
        wareOrderTaskService.save(wareOrderTaskEntity);
        List<OrderItemVo> locks = wareSkuLockVo.getLocks();
        List<SkuWareHasStock> skuWareHasStocks = locks.stream().map((orderItemVo -> {
            SkuWareHasStock skuWareHasStock = new SkuWareHasStock();
            Long skuId = orderItemVo.getSkuId();
            skuWareHasStock.setSkuId(skuId);
            skuWareHasStock.setNum(orderItemVo.getCount());
            //查询该商品所有有库存的仓库
            List<Long> wareId = this.baseMapper.listWareHasStock(skuId);
            skuWareHasStock.setWareId(wareId);
            return skuWareHasStock;
        })).collect(Collectors.toList());

        for (SkuWareHasStock skuWareHasStock : skuWareHasStocks) {
            Boolean allLock = false;
            List<Long> wareIds = skuWareHasStock.getWareId();
            //没有库存
            if (wareIds == null || wareIds.size() == 0){
                throw new NoStockException(skuWareHasStock.skuId);
            }else {

                for (Long wareId : wareIds) {
                    //锁定库存
                    Long count = this.baseMapper.lockWareStock(skuWareHasStock.getSkuId(),wareId,skuWareHasStock.getNum());
                    if (count == 1){
                        allLock = true;

                        WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity(null,skuWareHasStock.getSkuId(),"",skuWareHasStock.getNum(),wareOrderTaskEntity.getId(),wareId,1);
                        wareOrderTaskDetailService.save(wareOrderTaskDetailEntity);

                        SkuLockedTo skuLockedTo = new SkuLockedTo();
                        skuLockedTo.setId(wareOrderTaskEntity.getId());
                        SkuLockedDetail skuLockedDetail = new SkuLockedDetail();
                        BeanUtils.copyProperties(wareOrderTaskDetailEntity,skuLockedDetail);
                        skuLockedTo.setDetail(skuLockedDetail);
                        //TODO 向MQ发送锁定成功
                        rabbitTemplate.convertAndSend("stock-event-exchange","stock.locked",skuLockedTo);
                        break;
                    }
                }
                if (!allLock){
                    //没有仓库能够锁住商品需要的库存
                    throw new NoStockException(skuWareHasStock.skuId);
                }
            }
        }
        return true;
    }
    @Data
    public static class SkuWareHasStock{
        private Long skuId;
        private Integer num;
        private List<Long> wareId;
    }
    /**被动解锁
     * 查询锁定库存信息
     * 有数据 证明锁成功
     *    查询订单信息
     *      订单不存在或者存在但被取消 解锁库存
     * 没有 锁库存业务出现异常 数据回滚
     * 其他无需操作
     * @param to
     */
    @Transactional
    @Override
    public void releaseStock(SkuLockedTo to) {
        Long taskId = to.getId();
        SkuLockedDetail detail = to.getDetail();
        Long id = detail.getId();
        WareOrderTaskDetailEntity byId = wareOrderTaskDetailService.getById(id);
        if (byId != null){
            WareOrderTaskEntity wareOrderTaskEntity = wareOrderTaskService.getById(taskId);
            String orderSn = wareOrderTaskEntity.getOrderSn();
            R r = orderFeignService.getStatusByOrderSn(orderSn);
            if (r.getCode() == 0){
                OrderVo order = r.getData(new TypeReference<OrderVo>() {
                });
                if (order == null || order.getStatus() == OrderConstants.OrderStatusEnum.CANCLED.getCode()){
                    //已锁定的库存
                    if (byId.getLockStatus() == 1){
                        //解锁库存
                        unLock(byId.getSkuId(),byId.getWareId(),byId.getSkuNum(),id);

                    }
                }
            }else {
                throw new RuntimeException("订单远程调用失败");
            }
        }
    }
    //防止网络延迟，订单的取消状态未执行，解锁库存消息先接收后什么都没做，永远解锁库存
    //主动解锁
    @Transactional
    @Override
    public void releaseStock(OrderTo to) {
        String orderSn = to.getOrderSn();
        //查询工作表的库存状态
        WareOrderTaskEntity wareOrderTaskEntity = wareOrderTaskService.getByOrderSn(orderSn);
        List<WareOrderTaskDetailEntity> entities = wareOrderTaskDetailService.list(new LambdaQueryWrapper<WareOrderTaskDetailEntity>().
                eq(WareOrderTaskDetailEntity::getTaskId,wareOrderTaskEntity.getId()).eq(WareOrderTaskDetailEntity::getLockStatus,1));
        for (WareOrderTaskDetailEntity entity : entities) {
            //解锁
            unLock(entity.getSkuId(),entity.getWareId(),entity.getSkuNum(),entity.getId());
        }
    }
    @Transactional
    @Override
    public void reduceStock(String orderSn) {
        WareOrderTaskEntity wareOrderTaskEntity = wareOrderTaskService.getByOrderSn(orderSn);
        List<WareOrderTaskDetailEntity> entities = wareOrderTaskDetailService.list(new LambdaQueryWrapper<WareOrderTaskDetailEntity>().
                eq(WareOrderTaskDetailEntity::getTaskId,wareOrderTaskEntity.getId()).eq(WareOrderTaskDetailEntity::getLockStatus,1));
        for (WareOrderTaskDetailEntity entity : entities) {
            reduce(entity.getSkuId(),entity.getWareId(),entity.getSkuNum(),entity.getId());
        }
    }

    private void reduce(Long skuId, Long wareId, Integer skuNum, Long id) {
        //减库存,解锁
        this.baseMapper.reduceStock(skuId,wareId,skuNum);
        //修改订单详情的状态
        WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity();
        wareOrderTaskDetailEntity.setId(id);
        wareOrderTaskDetailEntity.setLockStatus(3);
        wareOrderTaskDetailService.updateById(wareOrderTaskDetailEntity);
    }

    private void  unLock(Long skuId, Long wareId, Integer skuNum, Long id){
        //解锁库存
        this.baseMapper.unLockSkuStock(skuId,wareId,skuNum);
        //修改订单详情的状态
        WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity();
        wareOrderTaskDetailEntity.setId(id);
        wareOrderTaskDetailEntity.setLockStatus(2);
        wareOrderTaskDetailService.updateById(wareOrderTaskDetailEntity);
    }
}